/* -*- mode: c++ -*- */
#ifndef SYMBOL_H_
#define SYMBOL_H_
#ifndef TOKEN_H_
#   include "token.h"
#endif

/* symbol.h - define symbols and symbol table.
 *
 */
class   TSymbol;

class   TSymbolAtom
    {
protected:
    enum
        {
        F_TERMINAL      = 0x0001,
        F_NONTERMINAL   = 0x0002,
        F_ACTION        = 0x0004,
        F_RULE          = 0x0008,
        };
    string  Name_;
public:
    int     Flags;
    int     Value       = -1;
    vector<unique_ptr<TSymbol>>     Derives;
    const string& Name()                { return Name_; }
    virtual ~TSymbolAtom()              {}
    bool IsTerminal()                   { return Flags&F_TERMINAL; }
    bool IsNonterminal()                { return Flags&F_NONTERMINAL; }
    bool IsAction()                     { return Flags&F_ACTION; }
    bool IsRule()                       { return Flags&F_RULE; }
    virtual TTokenIndex TokenIndex()    { return -1; }
//    virtual vector<TSymbol*>::iterator begin()   = 0;
//    virtual vector<TSymbol*>::iterator end()     = 0;
//    virtual void InsertSymbol(TSymbol* Symbol, int Pos=-1)  = 0;
    };

class   TSymbolInstance;
class   TSymbol
    {
    TSymbolAtom*        AtomPtr;
    TSymbolInstance*    InstancePtr;
public:
    TSymbol(TSymbolAtom* Atom) : AtomPtr(Atom), InstancePtr(nullptr) {}
    TSymbolAtom*    operator->() { return AtomPtr; }
    };

// is the only point of TSymbolInstance to keep from
// wasting some space? In that case, just adding a
// "instance ptr" to TSymbol is probably about as
// cheap. custom allocators with one big deleter
// probably save more than my derived inheritance scheme.

class   TSymbolInstance : public TSymbol
    {
public:
    TSymbol*    Parent;
    TSymbol*    Source;
    };


class   TSymbolTable
    {
public:
    TSymbolTable(unique_ref<TTokens> Tokens_) : Tokens(Tokens_) {}
    TSymbolTable& operator=(TSymbolTable&) = delete;
   ~TSymbolTable();
    TSymbol    Find(string Name);
    TSymbol    FindTerminal(string Name);
//        TSymbol*                        NewSymbol(string Name, bool Terminal, TTokenIndex Index, 
    TSymbol NewTerminal(TTokenIndex Index);
//    unique_ptr<TSymbolInstance>     NewTerminal(string Name, TTokenIndex Index);
    TSymbol NewNonterminal(TTokenIndex Index);
    TSymbol            NewRule(string Name);
//    unique_ptr<TSymbol>             NewTerminal(string Name);
//    unique_ptr<TSymbol>             NewNonTerminal(string Name);
//    void    AddUniqueSymbol(unique_ptr<TSymbolAtom> Symbol);
    map<string,unique_ptr<TSymbolAtom>> Atoms;
    vector<TSymbol>    NonTerminals;
    vector<TSymbol>    Terminals;
    vector<TSymbol>    Rules;

    unique_ref<TTokens> Tokens;
private:
    TSymbol AddAtom(unique_ptr<TSymbolAtom> Atom, vector<TSymbol>& Array);
    TSymbolAtom*        FindAtom(string Name);
    };


#endif /* SYMBOL_H_ */
